package com.skyline.wo.controller;

import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStream;
import java.net.URLDecoder;
import java.util.HashMap;
import java.util.Map;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import net.imagine.core.ImageInfo;
import net.imagine.core.ImageOperations;
import net.imagine.core.ResultState;
import net.imagine.core.engine.ImageEngine;
import net.imagine.provider.skyline.ImageCropResult;
import net.imagine.provider.skyline.ImageCutter;
import net.imagine.provider.skyline.ImageResizeResult;
import net.imagine.provider.skyline.MultipartImageResizeTask;
import net.imagine.provider.skyline.SkylineImageCropTask;
import net.imagine.provider.skyline.SkylineImagineUtils;

import org.apache.commons.io.FileUtils;
import org.apache.commons.io.FilenameUtils;
import org.apache.commons.io.IOUtils;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.codehaus.jackson.JsonEncoding;
import org.codehaus.jackson.JsonGenerationException;
import org.codehaus.jackson.JsonGenerator;
import org.codehaus.jackson.map.JsonMappingException;
import org.codehaus.jackson.map.ObjectMapper;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;
import org.springframework.util.StringUtils;
import org.springframework.web.multipart.MultipartFile;
import org.springframework.web.multipart.MultipartHttpServletRequest;

import com.skyline.common.util.Constant;
import com.skyline.common.util.WebHelper;
import com.skyline.spot.model.Spot;
import com.skyline.spot.service.SpotService;
import com.skyline.user.model.User;
import com.skyline.user.service.PersonalInfoService;
import com.skyline.wo.model.Album;
import com.skyline.wo.model.Photo;
import com.skyline.wo.service.AlbumService;

/**
 * SWF批量文件上传用到的上传类，不能使用SpringMVC,会返回406<br/>
 * 必须由Spring来管理，且beanId必须为uploadAction<br/>
 * 具体请参见imagine框架
 * 
 * @author wuqh
 * */
@Component("uploadAction")
public class UploadController {
	private static final Log LOGGER = LogFactory.getLog(UploadController.class);
	private static final String URL_SUFFIX = "html";
	private ObjectMapper objectMapper = new ObjectMapper();

	@Value("${imagine.localStorePath}")
	private String basePath;
	@Value("${album.uploadphoto.filesize}")
	private long maxSizePerFile;

	@Autowired
	private ImageEngine imagine;
	@Value("${imagine.baseSize1},${imagine.baseSize2}")
	private int[] baseSizes;
	@Autowired
	private ImageOperations operations;
	@Autowired
	private ImageCutter crop;
	@Value("${imagine.protraitSize}")
	private int portraitSize;

	@Autowired
	private PersonalInfoService personalInfoService;
	@Autowired
	private SpotService spotService;
	@Autowired
	private AlbumService albumService;

	public void batchUpload(HttpServletRequest request, HttpServletResponse response)
			throws IOException {
		String albumIdStr = request.getParameter("albumid");
		String userIdStr = request.getParameter("userid");
		if (!"POST".equals(request.getMethod())) {
			response.sendRedirect(buildRecirectPath(request, "/album/bupload/" + albumIdStr, null));
		}
		long userId = Long.parseLong(userIdStr);
		long albumId = Long.parseLong(albumIdStr);
		MultipartFile file = ((MultipartHttpServletRequest) request).getFile("file");
		// 本地存放路径生成
		if (file == null) {
			Map<String, Object> jsonMap = resultToJsonMap(ResultState.NO_FILE_EXIST, null);
			OutputStream out = response.getOutputStream();
			outputJsonResult(out, jsonMap);
			return;
		}
		File localFile = generateLocalFile(userId, albumId, file.getOriginalFilename());
		// 保存文件
		ResultState result = storeFileInLocal(localFile, file);
		// 输出结果
		Map<String, Object> jsonMap = resultToJsonMap(result, localFile.getAbsolutePath());
		OutputStream out = response.getOutputStream();
		outputJsonResult(out, jsonMap);
	}

	public void delUploaded(HttpServletRequest request, HttpServletResponse response)
			throws IOException {
		String filePath = request.getParameter("photo_file");
		if ("GET".equals(request.getMethod())) {
			filePath = URLDecoder.decode(filePath, "UTF-8");
		}
		Map<String, Object> jsonMap = null;
		OutputStream out = response.getOutputStream();
		File file = null;
		if(StringUtils.hasLength(filePath)) {
			file = new File(filePath);
		}
		if (file == null || !file.exists()) {
			jsonMap = toJsonMap(false, "文件不存在");
			outputJsonResult(out, jsonMap);
			return;
		}
		try {
			FileUtils.forceDelete(file);
		} catch (IOException e) {
			LOGGER.warn("删除图片文件失败", e);
			jsonMap = toJsonMap(false, "删除失败");
			outputJsonResult(out, jsonMap);
			return;
		}
		jsonMap = toJsonMap(true, "成功");
		outputJsonResult(out, jsonMap);
	}

	/**
	 * 此功能必须和应用位于同一个session中
	 * 
	 * */
	public void uploadPortrait(HttpServletRequest request, HttpServletResponse response)
			throws IOException {
		if (!"POST".equals(request.getMethod())) {
			response.sendRedirect(buildRecirectPath(request, "/user/photoupload", null));
		}
		
		User user = (User) WebHelper.getSessionAttribute(request, Constant.SESSION_USER);
		Map<String, Object> jsonMap = null;
		if (user == null) {
			jsonMap = toJsonMap(false, "修改照片描述必须登录");
			jsonMap.put("logined", Boolean.FALSE);
			OutputStream out = response.getOutputStream();
			outputJsonResult(out, jsonMap);
			return;
		}

		try {
			long userId = user.getId();
			Album album = albumService.getUserPortraitAlbum(userId);
			long albumId = album.getId();

			MultipartFile file = ((MultipartHttpServletRequest) request).getFile("file");
			if (file == null) {
				jsonMap = resultToJsonMap(ResultState.NO_FILE_EXIST, null);
				OutputStream out = response.getOutputStream();
				outputJsonResult(out, jsonMap);
				return;
			}
			MultipartImageResizeTask resizeTask = new MultipartImageResizeTask(file, baseSizes,
					null, false);
			resizeTask.setAlbumId(albumId);
			resizeTask.setUserId(userId);
			resizeTask.setSupportMulitFrame(false);
			ImageResizeResult processResult = imagine.processSingleImage(basePath, resizeTask);
			ResultState resultState = processResult.getResultState();
			if (resultState != ResultState.SUCCESS) {
				jsonMap = resultToJsonMap(resultState, null);
				OutputStream out = response.getOutputStream();
				outputJsonResult(out, jsonMap);
				return;
			}
			Photo portrait = albumService.createPortraitPhoto(user, album, processResult);

			String smallFile = portrait.getSmallFile();
			String ext = portrait.getExt();
			String remoteFileKey = smallFile + '.' + ext;

			SkylineImageCropTask cropTask = new SkylineImageCropTask(remoteFileKey, portraitSize);
			cropTask.setAlbumId(albumId);
			cropTask.setUserId(userId);
			ImageCropResult cropResult = crop.processImage(basePath, cropTask);
			String portraitFile = cropResult.getFileKey();

			personalInfoService.changeUserPortrait(userId, portraitFile);
			user.setPortrait(portraitFile);
			WebHelper.setSessionAttribute(request, Constant.SESSION_USER, user);

			jsonMap = toJsonMap(true, "上传头像成功");
			jsonMap.put("fileKey", remoteFileKey);
		} catch (Exception e) {
			LOGGER.warn("上传头像失败", e);
			jsonMap = toJsonMap(false, "上传头像失败，请稍候重试");
		}
		jsonMap.put("logined", Boolean.TRUE);
		OutputStream out = response.getOutputStream();
		outputJsonResult(out, jsonMap);
	}

	public void uploadSpotPortrait(HttpServletRequest request, HttpServletResponse response)
			throws IOException {
		String spotIdStr = request.getParameter("spotId");
		String albumIdStr = request.getParameter("albumId");
		if (!"POST".equals(request.getMethod())) {
			response.sendRedirect(buildRecirectPath(request, "/spot/spotId/editPortrait", null));
		}
		long spotId = Long.parseLong(spotIdStr);
		long albumId = Long.parseLong(albumIdStr);
		User user = (User) WebHelper.getSessionAttribute(request, Constant.SESSION_USER);
		Map<String, Object> jsonMap = null;
		if (user == null) {
			jsonMap = toJsonMap(false, "修改照片描述必须登录");
			jsonMap.put("logined", Boolean.FALSE);
			OutputStream out = response.getOutputStream();
			outputJsonResult(out, jsonMap);
			return;
		}

		try {
			Album album =albumService.getAlbumById(albumId);
			Spot spot=spotService.getSpot(spotId);
			MultipartFile file = ((MultipartHttpServletRequest) request).getFile("file");
			if (file == null) {
				jsonMap = resultToJsonMap(ResultState.NO_FILE_EXIST, null);
				OutputStream out = response.getOutputStream();
				outputJsonResult(out, jsonMap);
				return;
			}
			MultipartImageResizeTask resizeTask = new MultipartImageResizeTask(file, baseSizes,
					null, false);
			resizeTask.setAlbumId(albumId);
			resizeTask.setUserId(spotId);
			resizeTask.setSupportMulitFrame(false);
			ImageResizeResult processResult = imagine.processSingleImage(basePath, resizeTask);
			ResultState resultState = processResult.getResultState();
			if (resultState != ResultState.SUCCESS) {
				jsonMap = resultToJsonMap(resultState, null);
				OutputStream out = response.getOutputStream();
				outputJsonResult(out, jsonMap);
				return;
			}
			/**
			 * 构造一个spot的user
			 */
			User tempuser=new User();
			tempuser.setId(spot.getId());
			tempuser.setNickname(spot.getName());
			tempuser.setPortrait(spot.getPortrait());
			Photo portrait = albumService.createPortraitPhoto(tempuser, album, processResult);

			String smallFile = portrait.getSmallFile();
			String ext = portrait.getExt();
			String remoteFileKey = smallFile + '.' + ext;

			SkylineImageCropTask cropTask = new SkylineImageCropTask(remoteFileKey, portraitSize);
			cropTask.setAlbumId(albumId);
			cropTask.setUserId(spotId);
			ImageCropResult cropResult = crop.processImage(basePath, cropTask);
			String portraitFile = cropResult.getFileKey();
			spotService.updateSpotPortrait(spotId, portraitFile);
			
			spot.setPortrait(portraitFile);
			//WebHelper.setSessionAttribute(request, Constant.SESSION_USER, user);

			jsonMap = toJsonMap(true, "上传头像成功");
			jsonMap.put("fileKey", remoteFileKey);
		} catch (Exception e) {
			LOGGER.warn("上传头像失败", e);
			jsonMap = toJsonMap(false, "上传头像失败，请稍候重试");
		}
		jsonMap.put("logined", Boolean.TRUE);
		OutputStream out = response.getOutputStream();
		outputJsonResult(out, jsonMap);
	}
	private void outputJsonResult(OutputStream out, Map<String, Object> jsonMap)
			throws JsonGenerationException, JsonMappingException, IOException {
		// JsonEncoding encoding =
		// getEncoding(outputMessage.getHeaders().getContentType());
		JsonGenerator jsonGenerator = objectMapper.getJsonFactory().createJsonGenerator(out,
				JsonEncoding.UTF8);
		objectMapper.writeValue(jsonGenerator, jsonMap);
	}

	private Map<String, Object> resultToJsonMap(ResultState result, String filePath) {
		switch (result) {
		case SUCCESS:
			return toJsonMap(true, "成功", filePath);
		case FILE_TO_LARGE:
			return toJsonMap(false, "文件过大", filePath);
		case STORE_FAILED:
			return toJsonMap(false, "保存失败", filePath);
		case NOT_IMAGE:
			return toJsonMap(false, "不是图片", filePath);
		case EXCEED_MAX_CAPACITY:
			return toJsonMap(false, "超过容量", filePath);
		case UNKOWN_FAILED:
			return toJsonMap(false, "未知错误", filePath);
		default:
			return toJsonMap(false, "未知错误", filePath);
		}
	}

	private Map<String, Object> toJsonMap(boolean isSuccess, String errMsg) {
		return toJsonMap(isSuccess, errMsg, null);
	}

	// private Map<String, Object> toJsonMap(boolean isSuccess, String errMsg,
	// Map<String, Object> jsonMap) {
	// return toJsonMap(isSuccess, errMsg, null, jsonMap);
	// }

	private Map<String, Object> toJsonMap(boolean isSuccess, String errMsg, String filePath) {
		Map<String, Object> jsonMap = new HashMap<String, Object>();
		jsonMap.put("success", Boolean.valueOf(isSuccess));
		jsonMap.put("errmsg", errMsg);
		if (isSuccess && StringUtils.hasLength(filePath)) {
			jsonMap.put("file", filePath);
		}
		return jsonMap;
	}

	// private Map<String, Object> toJsonMap(boolean isSuccess, String errMsg,
	// String filePath,
	// Map<String, Object> jsonMap) {
	// if (jsonMap == null) {
	// jsonMap = new HashMap<String, Object>();
	// }
	// jsonMap.put("success", Boolean.valueOf(isSuccess));
	// jsonMap.put("errmsg", errMsg);
	// if (isSuccess && StringUtils.hasLength(filePath)) {
	// jsonMap.put("file", filePath);
	// }
	// return jsonMap;
	// }

	private File generateLocalFile(long userId, long albumId, String oriFilename) {
		String baseName = FilenameUtils.getBaseName(oriFilename);
		String ext = FilenameUtils.getExtension(oriFilename);
		String filePath = SkylineImagineUtils.generateFilePath(basePath, userId, albumId,
				oriFilename);
		File localFile = new File(filePath);
		int num = 0;
		while (localFile.exists()) {// 处理同名文件
			StringBuffer tempFilename = new StringBuffer(baseName);
			tempFilename.append('(').append(num).append(')').append('.').append(ext);
			filePath = SkylineImagineUtils.generateFilePath(basePath, userId, albumId, tempFilename
					.toString());
			localFile = new File(filePath);
			num++;
		}
		return localFile;
	}

	private ResultState storeFileInLocal(File localFile, MultipartFile file) {
		// 判断文件是否过大
		long actualSize = file.getSize();
		if (actualSize > maxSizePerFile) {
			return ResultState.FILE_TO_LARGE;
		}
		// TODO 判断是否到达容量上限

		// 保存到本地文件
		try {
			FileOutputStream out = FileUtils.openOutputStream(localFile);
			IOUtils.copy(file.getInputStream(), out);
		} catch (IOException e) {
			LOGGER.warn("写入本地临时文件失败", e);
			return ResultState.STORE_FAILED;
		}

		// 判断文件是否为图片格式
		ImageInfo info = operations.showImageInfo(localFile.getAbsolutePath());
		if (info == null) {
			try {
				FileUtils.forceDelete(localFile);
			} catch (IOException e) {
				LOGGER.warn("删除非图片文件失败", e);
			}

			return ResultState.NOT_IMAGE;
		}
		return ResultState.SUCCESS;
	}

	protected String buildRecirectPath(HttpServletRequest request, String baseUrl, String paramStr) {
		if (StringUtils.hasLength(paramStr)) {
			return request.getContextPath() + baseUrl + URL_SUFFIX + "?" + paramStr;
		} else {
			return request.getContextPath() + baseUrl + URL_SUFFIX;
		}

	}
}
